{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 利用卷积神经网络生成的Mnist 手写数字集识别系统Web版"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  \n",
    "##  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  1. 运行以下代码启动识别系统web服务端"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "   WARNING: This is a development server. Do not use it in a production deployment.\n",
      "   Use a production WSGI server instead.\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on http://0.0.0.0:10170/ (Press CTRL+C to quit)\n"
     ]
    }
   ],
   "source": [
    "#!/usr/bin/env python\n",
    "# -*- coding: utf-8 -*-\n",
    "\n",
    "\n",
    "import re\n",
    "import json\n",
    "import base64\n",
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "import tensorflow.keras as keras\n",
    "from flask import Flask, render_template, request, jsonify\n",
    "from tensorflow.keras.preprocessing.image import img_to_array, load_img\n",
    "\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "model_file = './model/model.h5'\n",
    "global model\n",
    "model = keras.models.load_model(model_file)\n",
    "\n",
    "\n",
    "@app.route('/')\n",
    "def index():\n",
    "    response = {}\n",
    "    return render_template(\"index.html\", **response) \n",
    "\n",
    "@app.route('/predict/', methods=['Get', 'POST'])\n",
    "def preditc():\n",
    "    parseImage(request.get_data())\n",
    "    img = img_to_array(load_img('output.png', target_size=(28, 28), color_mode=\"grayscale\")) / 255.\n",
    "    img = np.expand_dims(img, axis=0)\n",
    "    code = model.predict_classes(img)[0]\n",
    "    response = {}\n",
    "    response['code'] = int(code)\n",
    "    print(response)\n",
    "    return jsonify(response)\n",
    "\n",
    "\n",
    "def parseImage(imgData):\n",
    "    imgStr = re.search(b'base64,(.*)', imgData).group(1)\n",
    "    with open('./output.png', 'wb') as output:\n",
    "        output.write(base64.decodebytes(imgStr))\n",
    "    \n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run(host=\"0.0.0.0\", port=10170, debug=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 运行以下代码 自动访问 web版识别系统。\n",
    "##     也可以直接在浏览器中打开 [Mnist手写数字识别系统](http://localhost:10170/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<iframe src=\"http://localhost:10170\" width=100% height=600></iframe>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%%html\n",
    "<iframe src=\"http://localhost:10170\" width=100% height=600></iframe>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. 思考与讨论"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 以下代码是识别模型的训练过程，\n",
    "### 1. 试修改隐藏层神经元数量，和模型的训练轮次，重新训练模型；\n",
    "### 2. 重新运行以上的web服务端代码，观察并分析模型的准确度。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#!/usr/bin/env python\n",
    "# -*- coding: utf-8 -*-\n",
    "\n",
    "\n",
    "import tensorflow as tf\n",
    "import tensorflow.keras as keras\n",
    "from tensorflow.keras import Sequential\n",
    "from tensorflow.keras.layers import Flatten, Dense, Conv2D, MaxPooling2D, Dropout, MaxPool2D\n",
    "from tensorflow.keras.datasets import mnist\n",
    "from tensorflow.keras import backend as K\n",
    "import json\n",
    "\n",
    "\n",
    "batch_size = 128\n",
    "num_classes = 10\n",
    "epochs = 10\n",
    "\n",
    "# input image dimensions\n",
    "img_rows, img_cols = 28, 28\n",
    "\n",
    "# the data, shuffled and split between train and test sets\n",
    "(x_train, y_train), (x_test, y_test) = mnist.load_data()\n",
    "\n",
    "if K.image_data_format() == 'channels_first':\n",
    "    x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)\n",
    "    x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)\n",
    "    input_shape = (1, img_rows, img_cols)\n",
    "else:\n",
    "    x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)\n",
    "    x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)\n",
    "    input_shape = (img_rows, img_cols, 1)\n",
    "    \n",
    "x_train = x_train.astype('float32') / 255\n",
    "x_test = x_test.astype('float32') / 255\n",
    "\n",
    "print('x_train shape:', x_train.shape)\n",
    "print(x_train.shape[0], 'train samples')\n",
    "print(x_test.shape[0], 'test samples')\n",
    "\n",
    "# convert class vectors to binary class matrices\n",
    "y_train = keras.utils.to_categorical(y_train, num_classes)\n",
    "y_test = keras.utils.to_categorical(y_test, num_classes)\n",
    "print(input_shape)\n",
    "\n",
    "# 构建网络\n",
    "model = Sequential()\n",
    "# 第一个卷积层，32个卷积核，大小５x5，卷积模式SAME,激活函数relu,输入张量的大小\n",
    "model.add(Conv2D(filters=32, kernel_size=(5, 5), padding='Same', activation='relu',\n",
    "                 input_shape=(28, 28, 1)))\n",
    "model.add(Conv2D(filters=32, kernel_size=(5, 5), padding='Same', activation='relu'))\n",
    "# 池化层,池化核大小２x2\n",
    "model.add(MaxPool2D(pool_size=(2, 2)))\n",
    "# 随机丢弃四分之一的网络连接，防止过拟合\n",
    "model.add(Dropout(0.25))\n",
    "model.add(Conv2D(filters=64, kernel_size=(3, 3), padding='Same', activation='relu'))\n",
    "model.add(Conv2D(filters=64, kernel_size=(3, 3), padding='Same', activation='relu'))\n",
    "model.add(MaxPool2D(pool_size=(2, 2), strides=(2, 2)))\n",
    "model.add(Dropout(0.25))\n",
    "# 全连接层,展开操作，\n",
    "model.add(Flatten())\n",
    "# 添加隐藏层神经元的数量和激活函数\n",
    "model.add(Dense(256, activation='relu'))\n",
    "model.add(Dropout(0.25))\n",
    "# 输出层\n",
    "model.add(Dense(10, activation='softmax'))\n",
    "model.summary()\n",
    "model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])\n",
    "\n",
    "\n",
    "model.fit(x_train, y_train, batch_size=batch_size,epochs=epochs,verbose=1,validation_data=(x_test, y_test))\n",
    "score = model.evaluate(x_test, y_test, verbose=0)\n",
    "print('Test loss:', score[0])\n",
    "print('Test accuracy:', score[1])\n",
    "\n",
    "\n",
    "with open('model.json', 'w') as outfile:\n",
    "    json.dump(model.to_json(), outfile)\n",
    "    \n",
    "model_file = 'model.h5'\n",
    "model.save(model_file)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
